/**
 * Copyright - Accor - All Rights Reserved www.accorhotels.com
 */
package com.my.imq.web.tools;

import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;

import org.springframework.util.ReflectionUtils;

import com.invient.vaadin.charts.InvientCharts.DateTimePoint;
import com.invient.vaadin.charts.InvientCharts.DateTimeSeries;
import com.my.imq.model.Broker;
import com.my.imq.web.tools.dto.BrokerDTO;
import com.my.imq.web.tools.dto.ChartDTO;
import com.my.imq.web.tools.dto.SeriesDTO;
import com.vaadin.ui.GridLayout;

/**
 * @author <a href="MABDELOUHAB">MABDELOUHAB</a>
 * created 22 févr. 2013
 * @since 
 * @version $Id$
 */
public class ChartBuilder
{
    /**
     * broker
     */
    private BrokerDTO broker;

    private GridLayout grid;

    private List<Chart> charts = new ArrayList<Chart>();
    
    private List<Broker> brokers;

    /**
     * @throws JAXBException 
     * 
     */
    public ChartBuilder( List<Broker> brokers )
    {
        this.brokers=brokers;
        //recuperation de la structure de confuguration des charts pour le broker
        getConfiguration( Constants.BROKER_CONF_PATH );
        buildGridChart();
    }

    /**
     * 
     * @param conf
     */
    private void getConfiguration( String conf )
    {
        ClassLoader cl = ChartBuilder.class.getClassLoader();
        InputStream xml = cl.getResourceAsStream( conf );

        JAXBContext jc;
        Unmarshaller unmarshaller;

        try
        {
            jc = JAXBContext.newInstance( BrokerDTO.class );
            unmarshaller = jc.createUnmarshaller();
            this.broker = (BrokerDTO) unmarshaller.unmarshal( xml );
        }
        catch ( JAXBException e )
        {
            e.printStackTrace();
        }
    }

    /**
     * 
     */
    private void buildGridChart()
    {
        if ( this.broker != null && this.broker.getCharts() != null )
        {
            int i = 0, j = 0;
            int numberColls = 2;
            int numberRows = 0;
            if ( this.broker.getCharts().size() % 2 == 0 )
            {
                numberRows = this.broker.getCharts().size() / numberColls;
            }
            else
            {
                numberRows = ( this.broker.getCharts().size() / numberColls ) + 1;
            }

            grid = new GridLayout( numberColls, numberRows );
            grid.setMargin( true );
            grid.setSpacing( true );

            for ( ChartDTO dto : this.broker.getCharts() )
            {

                Chart chart = new Chart( dto.getTitle() );
                charts.add( chart );
                for ( SeriesDTO serie : dto.getSeries() )
                {
                    chart.addSerie( serie.getName() );
                    populate(chart,serie,this.brokers);
                }
                grid.addComponent( chart, i, j );

                if ( i != numberColls - 1 )
                {
                    i = i + 1;
                }
                else
                {
                    i = 0;
                    j = j + 1;
                }
            }
        }
    }

    public void populate( Chart chart, SeriesDTO serie, List<Broker> brokers )
    {
        LinkedHashSet<DateTimePoint> points = new LinkedHashSet<DateTimePoint>();
        try
        {
            if ( serie != null )
            {

                if ( chart.getSeries().containsKey( serie.getName() ) )
                {
                    DateTimeSeries dateTimeSeries = chart.getSeries().get( serie.getName() );
                    Field field = ReflectionUtils.findField( Broker.class, (String) serie.getName() );
                    field.setAccessible( true );
                    for ( Broker broker : brokers )
                    {
                        String val = (String) field.get( broker );

                        points.add( new DateTimePoint( dateTimeSeries, broker.getTime(), Double.parseDouble( val ) ) );
                    }

                    dateTimeSeries.setSeriesPoints( points );
                }

            }
        }
        catch ( IllegalArgumentException e )
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        catch ( IllegalAccessException e )
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public void populate( List<Broker> brokers )
    {
        LinkedHashSet<DateTimePoint> points = new LinkedHashSet<DateTimePoint>();

        try
        {

            for ( Broker broker : brokers )
            {
                for ( Chart chart : charts )
                {
                    if ( chart.getSeries() != null )
                    {
                        Iterator it = chart.getSeries().entrySet().iterator();
                        while ( it.hasNext() )
                        {
                            Map.Entry pairs = (Map.Entry) it.next();
                            DateTimeSeries serie = (DateTimeSeries) pairs.getValue();
                            Field field = ReflectionUtils.findField( Broker.class, (String) pairs.getKey() );
                            field.setAccessible( true );
                            String val = (String) field.get( broker );
                            serie.addPoint( new DateTimePoint( serie, broker.getTime(), Double.parseDouble( val ) ) );
                        }
                    }

                }

            }

        }
        catch ( IllegalArgumentException e )
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        catch ( IllegalAccessException e )
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    /**
     * @return the grid
     */
    public GridLayout getGrid()
    {
        return grid;
    }

    /**
     * @param grid the grid to set
     */
    public void setGrid( GridLayout grid )
    {
        this.grid = grid;
    }

}
